package com.swak.vertx.protocol.http;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.swak.Constants;
import com.swak.entity.Result;
import com.swak.exception.BusinessException;
import com.swak.exception.ErrorCode;
import com.swak.exception.FluxInvokeException;
import com.swak.exception.SubjectException;
import com.swak.exception.ValidatorException;
import com.swak.utils.Lists;
import com.swak.utils.StringUtils;
import com.swak.vertx.protocol.http.converter.HttpMessageConverter;
import com.swak.vertx.transport.HttpConst;

import io.netty.handler.codec.http.HttpHeaderNames;
import io.vertx.core.eventbus.ReplyException;
import io.vertx.core.eventbus.ReplyFailure;
import io.vertx.ext.web.RoutingContext;

/**
 * 处理结果
 *
 * @author: lifeng
 * @date: 2020/3/29 20:16
 */
public class ResultHandler {

	private Logger logger = LoggerFactory.getLogger(ResultHandler.class);

	private List<HttpMessageConverter> converters = Lists.newArrayList();

	/**
	 * 添加转换器
	 *
	 * @param converter 转换器
	 */
	public void addConverter(HttpMessageConverter converter) {
		converters.add(converter);
	}

	/**
	 * 处理结果
	 *
	 * @param result  结果
	 * @param e       异常
	 * @param context 请求上下文
	 */
	public void handleResult(Object result, Throwable e, RoutingContext context) {

		// 如果有异常
		if (e != null) {
			this.handleError(e, context);
			return;
		}

		// 已经输出数据
		if (!this.canWrite(context)) {
			return;
		}

		try {
			// 通过转换器输出
			if (result != null) {
				for (HttpMessageConverter converter : converters) {
					if (converter.canWrite(result.getClass())) {
						converter.write(result, context.response());
					}
				}
			}
		} catch (Exception ex) {
			this.handleError(ex, context);
			return;
		}

		// 允许返回 void 但需自己实现输出
		if (this.canWrite(context)) {
			context.response().putHeader(HttpHeaderNames.CONTENT_TYPE, HttpConst.APPLICATION_JSON);
			context.response().end(Result.success(StringUtils.EMPTY).toJson());
		}
		return;
	}

	/**
	 * 处理错误
	 *
	 * @param e       异常
	 * @param context 请求上下文
	 */
	public void handleError(Throwable e, RoutingContext context) {

		// 已经输出数据
		if (!this.canWrite(context)) {
			return;
		}

		// 输出错误信息
		Result result = Result.error(ErrorCode.SERVER_ERROR);

		try {
			// 实际的错误
			Throwable cause = e.getCause() != null ? e.getCause() : e;

			// 验证、特定异常 -- 不需要打印
			if (cause instanceof ValidatorException) {
				result = Result.error(((ValidatorException) cause).getErrors());
			}
			// 账号业务异常
			else if (cause instanceof SubjectException) {
				result = Result.error(((SubjectException) cause).getError());
			}
			// 还没有到业务: 在eventbus 中发生的异常
			else if (cause instanceof ReplyException) {
				ReplyException realError = (ReplyException) cause;
				ReplyFailure replyFailure = realError.failureType();
				if (replyFailure == ReplyFailure.TIMEOUT) {
					result = Result.error("服务访问超时！");
				} else if (replyFailure == ReplyFailure.NO_HANDLERS || replyFailure == ReplyFailure.RECIPIENT_FAILURE) {
					result = Result.error("服务丢失！");
				}
			}
			// 业务异常
			else if (cause instanceof BusinessException) {
				result = Result.error(((BusinessException) cause).getMessage());
			}

			// 其他错误 输出错误信息
			if (!(cause instanceof ValidatorException || cause instanceof FluxInvokeException
					|| cause instanceof BusinessException)) {
				logger.error("{}", context.request().uri(), cause);
			}
		} finally {
			// 输出信息
			context.put(Constants.EXCEPTION_NAME, e);
			context.response().putHeader(HttpHeaderNames.CONTENT_TYPE, HttpConst.APPLICATION_JSON);
			context.response().end(result.toJson());
		}
	}

	/**
	 * 是否可以输出数据
	 */
	private boolean canWrite(RoutingContext context) {
		return !context.response().closed() && !context.response().ended();
	}
}